package wzw.jdbc;


/**
 * <p>数据连接池管理。</p>
 * @author	WUZEWEN on 2006-3-7
 * @version	1.0
 * @see		Object#equals(java.lang.Object)
 * @see		Object#hashCode()
 * @since	JDK5
 */

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.sql.DataSource;

import org.apache.log4j.Logger;

import wzw.util.FileUtils;

import com.kingcore.framework.context.DataSourceManager;


public class ConnectionManager implements DataSourceManager{ //连接池类
	
//	/**
//	 * 连接池对象类
//	 */
//	class ConnectionPool { //连接池属性
//		
//		private int checkedOut;
//		private Vector<PooledConnection> freeConnections;
//		private int maxConn;
//		private String name;
//		private String user;
//		private String password;
//		private String URL;
//		
//		public synchronized void freeConnection(PooledConnection con) {
//			
//			freeConnections.addElement(con);
//			checkedOut--;
//			log.info( (new StringBuffer("释放后连接池")).append(name)
//							.append("中用掉")
//							.append(checkedOut)
//							.append("/")
//							.append(maxConn)
//							.append("个连接") );
//			notifyAll();
//		}
//		
//		/**
//		 * get a connection from a Connection Collection. 
//		 * @return
//		 */
//		public synchronized PooledConnection getConnection() throws SQLException{
//			PooledConnection con = null;
//			if (freeConnections.size() > 0) {
//				con = freeConnections.firstElement();  //获取第一个，用完释放放在最后一位。
//				freeConnections.removeElementAt(0);
////				con = freeConnections.lastElement();
////				freeConnections.removeElementAt( freeConnections.size()-1 );
//				try {
//					if (con == null ) {   // || con.isClosed()
//						log.info( (new StringBuffer("从连接池")).append(name)
//									.append("删除一个无效连接") );
//						con = getConnection();
//						return con ;
//					}
//				} catch (SQLException e) {
//					log.info( (new StringBuffer("从连接池")).append(name)
//									.append("删除一个无效连接") );
//					con = getConnection();
//				}
//			} else if (maxConn == 0 || checkedOut < maxConn) {
//				con = newConnection();
//			} else {
//				log.info( (new StringBuffer("连接池")).append(name)
//								.append("所有连接已经被使用了") );
//			}
//
//			if (con != null) {
//				checkedOut++;
//				con.isConnClosed = false;  //设置为在使用中的状态
//				log.info( (new StringBuffer("正在使用")).append(name)
//								.append("连接池中的")
//								.append(checkedOut)
//								.append("/")
//								.append(maxConn)
//								.append("个连接") );
//			}
//			return con;
//		}
//		
//		public synchronized Connection getConnection(long timeout) throws SQLException {
//			long startTime = (Calendar.getInstance().getTime()).getTime();
//			Connection con;
//			while ( (con = getConnection()) == null) {
//				try {
//					wait(timeout);
//				}
//				catch (InterruptedException interruptedexception) {}
//				if ( (Calendar.getInstance().getTime()).getTime() - startTime >= timeout) {
//					return null;
//				}
//			}
//			return con;
//		}
//		/**
//		 * release all Connections from Collection.
//		 *
//		 */
//		public synchronized void release() {
//			for (Enumeration allConnections = freeConnections.elements();
//			allConnections.hasMoreElements(); ) {
//				Connection con = (Connection) allConnections.nextElement();
//				try {
//					con.close();
//					log.info( (new StringBuffer("关闭连接池")).append(name)
//								.append("中的一个连接") );
//				}
//				catch (SQLException e) {
//					log.info( (new StringBuffer("无法关闭连接池")).append(name)
//								.append("中的连接")
//								.append("\n")
//								.append( e.getMessage() ) );
//				}
//			}
//			
//			freeConnections.removeAllElements();
//		}
//		
//		/**
//		 * create a new Connection object.
//		 * @return
//		 */
//		private PooledConnection newConnection() throws SQLException{
//			Connection con = null;
//			try {
//				if (user == null) {
//					con = DriverManager.getConnection(URL);
//				} else {
//					con = DriverManager.getConnection(URL, user, password);
//				}
//				log.info( (new StringBuffer("连接池")).append(name)
//									.append("创建一个新的连接") );
//			} catch (SQLException e) {
//				log.info( (new StringBuffer("连接池")).append(name)
//						.append("无法创建下列URL的连接: ")
//						.append(URL)
//						.append("\n")
//						.append(e.getMessage())
//						.toString() );
//				//return null;
//				throw new SQLException( (new StringBuffer("连接池")).append(name)
//									.append("无法创建下列URL的连接: ")
//									.append(URL)
//									.append("\n")
//									.append(e.getMessage())
//									.toString() );
//			}
//			//return con;   
//			DatabaseManager databaseManager = createDatabaseManagerByDriver( this.driver );
//			return new PooledConnection(con, this.name, databaseManager);
//	}
//		
//		/**
//		 * Constructor of ConnectionPool Object.
//		 * @param name the pool name
//		 * @param URL the database connection url
//		 * @param user user for login database
//		 * @param password password for login database
//		 * @param maxConn the maximal connection ojbect number in the pool
//		 */
//		public ConnectionPool(String name, String URL, String user,
//				String password, int maxConn) {
//			freeConnections = new Vector();
//			this.name = name;
//			this.URL = URL;
//			this.user = user;
//			this.password = password;
//			this.maxConn = maxConn;
//		}
//	}
	
	private static ConnectionManager instance;
	private static int clients;
	private static String _filename = "db.properties";
	public static String errlog = "/err.log";
	private Vector drivers;
	private Hashtable pools;
	private Logger log = Logger.getLogger(ConnectionManager.class) ;	
	
	public static synchronized ConnectionManager getInstance() {
		if (instance == null) {
			instance = new ConnectionManager();
		}
		clients++;
		return instance;
	}

	protected boolean isConnectionClosed(String name, Connection conn) {
		ConnectionPool pool = (ConnectionPool) pools.get(name);
		return pool.isConnectionClosed(conn);
	}
	
	private ConnectionManager() {
		drivers = new Vector();
		pools = new Hashtable();
		/// init();
	}
	
	public void freeConnection(String name, PooledConnection con) {
		ConnectionPool pool = (ConnectionPool) pools.get(name);
		if (pool != null) {
			pool.freeConnection(con);
			clients--;
		}
	}

	private String defaultDataSourceName = "main";
	private String configPath;
	public Connection getConnection() throws SQLException{
		return getConnection( defaultDataSourceName );
	}
	
	public Connection getConnection(String name) throws SQLException{
//		if(name==null){ //修复bug
//			name = this.defaultDataSourceName;
//		}
		ConnectionPool pool = (ConnectionPool) pools.get(name);
		if(pool==null){ 
			pool = createPool(name);
		}
		if (pool != null) {
			return pool.getConnection();
		}
		else {
			return null;
		}
	}
	
	public Connection getConnection(String name, long time) throws Exception{
		ConnectionPool pool = (ConnectionPool) pools.get(name);
		if(pool==null) 
			createPool(name);
		if (pool != null) {
			return pool.getConnection(time);
		}
		else {
			return null;
		}
	}
	
	public synchronized void release() {
		if (--clients != 0) {
			return;
		}
		ConnectionPool pool;
		for (Enumeration allPools = pools.elements();
		allPools.hasMoreElements(); pool.release()) {
			pool = (ConnectionPool) allPools.nextElement();
			
		}
		for (Enumeration allDrivers = drivers.elements();
		allDrivers.hasMoreElements(); ) {
			Driver driver = (Driver) allDrivers.nextElement();
			try {
				DriverManager.deregisterDriver(driver);
				log.info( (new StringBuffer("撤销JDBC驱动程序 ")).
						append(driver.getClass().getName()).
						append("的注册") );
			}
			catch (SQLException e) {
				log.info( (new StringBuffer("无法撤销下列JDBC驱动程序的注册: "))
									.append( driver.getClass().getName()) );
			}
		}
		
	}
	
	private ConnectionPool createPool(String poolName) throws SQLException {
  
		Properties props = new Properties(); 
		int max = 0;
		try {
			String fileUrl = getConfigFile();
			//InputStream is = getClass().getResourceAsStream(filename);
			props.load( new FileInputStream(fileUrl) ); //is  //全部采用绝对路径，不要放在class目录下。
	
			String url = props.getProperty(String.valueOf(String.valueOf(poolName)).
					concat(".url"));
			if (url == null) {
				log.error( (new StringBuffer("没有为连接池"))
								.append(poolName)
								.append("指定URL") );
				return null;
			}
				 
			url = url.replace("${App_Home}", this.getAppHome() );
			String user = props.getProperty(String.valueOf(String.valueOf(
					poolName)).concat(".user"));
			String password = props.getProperty(String.valueOf(String.valueOf(
					poolName)).concat(".password"));
			String maxconn = props.getProperty(String.valueOf(String.valueOf(
					poolName)).concat(".maxconn"), "0");
			String driver = props.getProperty(String.valueOf(String.valueOf(
					poolName)).concat(".driver"));
			String databaseManagerName = props.getProperty(String.valueOf(String.valueOf(
					poolName)).concat(".databaseManagerName"));
			max = Integer.valueOf(maxconn.trim()).intValue();
			 
			ConnectionPool pool = new ConnectionPool(poolName, driver, databaseManagerName, url,
					user, password, max, max);
			pools.put(poolName, pool);
			return pool;
			
		} catch (Exception e) {

			log.info( (new StringBuffer("错误的最大连接数限制: "))
							.append(max)
							.append(" .连接池: ")
							.append(poolName), e );
			max = 0;
			
		}
		return null;
		//log("成功创建连接池".concat(String.valueOf(String.valueOf(poolName))));
		//System.out.println("成功创建连接池".concat(String.valueOf(String.valueOf(
		//    poolName)))); 
	}
	
	private String appHome = null;
	
	private void init() {
		Properties dbProps = new Properties();
		try {
			String filename = getConfigFile();
			InputStream is = getClass().getResourceAsStream(filename);
			dbProps.load(is);

			//需要时候再加载并创建pool最好
//			loadDrivers(dbProps);
//			createPools(dbProps);
			
		} catch (Exception e) {
			log.error( "不能读取属性文件. 请确保db.properties在指定的路径中" ,e );
			
			return;
		}
		// String logFile = dbProps.getProperty("logfile", "ConnectionManager.log"); // by wzw
		// errlog = dbProps.getProperty("errlog", "err.log"); //by wzw
//		try {
//			log = new PrintWriter(new FileWriter(logFile, true), true);
//		}
//		catch (IOException e) {
//			System.err.println("无法打开日志文件: ".concat(String.valueOf(String.valueOf(
//					logFile))));
//			log = new PrintWriter(System.err);
//		}

	}
	
	private String getConfigFile() {
		String url = getConfigPath() + File.separator + _filename;
		return FileUtils.convert2LinuxPath( url );
	}

	private void loadDrivers(Properties props) {
		String driverClasses = props.getProperty("drivers");
		for (StringTokenizer st = new StringTokenizer(driverClasses);
		st.hasMoreElements(); ) {
			String driverClassName = st.nextToken().trim();
			try {
				Driver driver = (Driver) Class.forName(driverClassName).newInstance();
				DriverManager.registerDriver(driver);
				drivers.addElement(driver);
				//log("成功注册JDBC驱动程序".concat(String.valueOf(String.valueOf(driverClassName))));
				//System.out.println("成功注册JDBC驱动程序".concat(String.valueOf(String.valueOf(
				//    driverClassName))));
			}
			catch (Exception e) {
				// log(String.valueOf(String.valueOf((new StringBuffer("无法注册JDBC驱动程序: ")).append(driverClassName).append(", 错误: ").append(e))));
				log.error( (new StringBuffer("无法注册JDBC驱动程序: "))
								.append(driverClassName)
								.append(", 错误: ")
								.append(e) );
			}
		}		
	}

	public String getDefaultDataSourceName() { 
		return this.defaultDataSourceName;
	}

	public void setDefaultDataSourceName(String defaultDataSourceName) {
		this.defaultDataSourceName = defaultDataSourceName;
		
	}

	/**
	 * @deprecated this method is ignored.
	 */
	public DataSource getDataSource() throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * @deprecated this method is ignored.
	 */
	public DataSource getDataSource(String arg0) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	public String getAppHome() {
		return appHome;
	}

	public void setAppHome(String app_Home) {
		appHome = app_Home;
	}

	@Override
	public void setConfigPath(String configPath) {
		this.configPath = configPath;
	}

	public String getConfigPath() {
		return configPath;
	}	

}
